
package com.x52im.rbchat.logic.chat_root.sendfile;

import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.eva.android.widget.DataLoadableActivity;
import com.eva.android.OpenFileUtil;
import com.eva.android.widget.WidgetUtils;
import com.eva.android.widget.alert.AlertDialog;
import com.eva.epc.common.file.FileHelper;
import com.eva.epc.common.util.CommonUtils;
import com.eva.framework.dto.DataFromServer;
import com.x52im.rbchat.MyApplication;
import com.x52im.rbchat.R;
import com.x52im.rbchat.network.http.bigfile.BigFileDownloadManager;
import com.x52im.rbchat.utils.IntentFactory;

import java.io.File;
import java.util.ArrayList;

/**
 * 大文件查看和下载处理界面。
 *
 * @author JackJiang
 * @since 4.3
 */
public class BigFileViewerActivity extends DataLoadableActivity
{
    private final static String TAG = BigFileViewerActivity.class.getSimpleName();

    /** 本次要查看的文件名 */
    private String fileName;
    /** 文件存储的目录：此目录末尾不需带"/"反斜线 */
    private String fileDir;
    /** 文件md5码 */
    private String fileMd5;
    /** 文件的理论总长度(此值并不是本地文件的实际长度，因为支持断点续传，可能并未完全下载完成) */
    private long fileLength;

    /** true表示当文件未完成或不存在时需要下载，否则不需要下载（这种情况对应用于我发出的文件） */
    private boolean canDownload = false;

    /** 文件查看界面上方显示的此文件类型图标（根据扩展名来决定的） */
    private ImageView mViewFileIcon = null;
    /** 文件查看界面下方显示的此文件名 */
    private TextView mViewFileName = null;
    /** 文件查看界面下方显示的此文件原始大小 */
    private TextView mViewFileSize = null;
    /** 文件查看界面下方的下载进度条（始果需要下载才显示哦） */
    private ProgressBar mDownloadProgress = null;
    /** 文件操作按钮：意义可以是打开、继续下载、暂停下载等，具体由文件下载状态和逻辑动态决定 */
    private Button mBtnOpr = null;
    /** 文件查看界面最下方的提示信息显示组件，比如当下载出错时会显示提示信息 */
    private TextView mViewHint = null;

    /** 文件下载状态观察者 */
    private BigFileDownloadManager.BigFileDownloadObserver downloadObserver = null;

    /**
     * 根据Activity的生命周期：本Activity每次从后台回到前台时调用本方法。
     */
    protected void onResume()
    {
        super.onResume();

        // 设置大文件下载任务观察者
        imc().getBigFileDownloadManager().setDownloadObserver(downloadObserver);
    }

    /**
     * 根据Activity的生命周期：本Activity每次从前台退到后台时调用本方法。
     */
    protected void onPause()
    {
        super.onPause();

        // 取消设置大文件下载任务观察者
        imc().getBigFileDownloadManager().setDownloadObserver(null);
    }

    /**
     * <p>
     * 解析从Intent中传过来的可能的数据本方法中实现.
     * 例如从上一个activity中传过来的数据，本方法被 {@link #init(Bundle)}调用。
     * </p>
     */
    @Override
    protected void initDataFromIntent()
    {
        //解析从intent中传过来的数据
        ArrayList intentDatas = IntentFactory.parseBigFileViewerIntent(getIntent());

        fileName = (String)intentDatas.get(0);
        fileDir = (String)intentDatas.get(1);
        fileMd5 = (String)intentDatas.get(2);
        fileLength = (Long) intentDatas.get(3);
        canDownload = (Boolean) intentDatas.get(4);

        Log.w(TAG, "【文件查看】Intent传进来的参数：fileName="+fileName+", fileDir="+fileDir
                +", fileMd5="+fileMd5+", fileLen="+fileLength);
        
        if(fileLength < 0)
            fileLength = 0;
    }

    /**
     * <p>
     * UI的初始化在此方法中实现.
     * 例如设置context对象以及给需要用的组件初始化（例如使用fingviewbyid方法获取所需的对象）等。
     * 本方法被 {@link #init(Bundle)}调用。
     */
    @Override
    protected void initViews(Bundle savedInstanceState)
    {
        customeTitleBarResId = R.id.big_file_viewer_activity_titleBar;
        setContentView(R.layout.big_file_viewer_activity);

        mViewFileIcon = (ImageView) findViewById(R.id.big_file_viewer_activity_fileiconView);
        mViewFileName = (TextView) findViewById(R.id.big_file_viewer_activity_filenameView);
        mViewFileSize = (TextView) findViewById(R.id.big_file_viewer_activity_filesizeView);
        mDownloadProgress = (ProgressBar) findViewById(R.id.big_file_viewer_activity_downloadbar);
        mBtnOpr = (Button) findViewById(R.id.big_file_viewer_activity_oprBtn);
        mViewHint = (TextView) findViewById(R.id.big_file_viewer_activity_hintView);

        mDownloadProgress.setVisibility(View.GONE);
        mViewHint.setVisibility(View.GONE);

        setTitle("文件信息");
        
        if(!checkInitParams())
            this.finish();

        // 设置文件图标
        this.mViewFileIcon.setImageDrawable(this.getResources().getDrawable(BigFileViewerActivity.getFileIconDrawableId(this.fileName)));
        // 文件名显示
        this.mViewFileName.setText(this.fileName);

        // 初始化观察者
        initObservers();
        // 初始化文件状态及相关UI显示
        initFileStatusForUI();
    }

    /**
     * 按钮事件处理。
     */
    protected void initListeners()
    {
        this.mBtnOpr.setOnClickListener(v -> {
            // 当文件不完整或不存在时需要下载（这种情况对应于收到的文件消息）
            if(canDownload)
            {
                // 大文件下载管理器
                BigFileDownloadManager bfdm = imc().getBigFileDownloadManager();

                // 当前界面中要查看的文件就是下载任务管理器中的文件
                if (bfdm.isCurrentFile(fileMd5))
                {
                    // 如果文件本身就已经下载完成，则直接进入打开逻辑，不需要再去根据管理器中的文件状态来决定
                    if(isLocalFileCompelte())
                    {
                        Log.d(TAG, "【文件查看-当前任务】[isFileCompelte=true]initListeners调用中。。");
                        doOpen();
                    }
                    // 未完成情况下
                    else
                    {
                        Log.d(TAG, "【文件查看-当前任务】[isFileCompelte=false]initListeners调用中。。（bfdm.getFileStatus()=" + bfdm.getFileStatus() + ")");

                        // 根据下载管理器中当前文件的下载状态来决定按钮的事件响应
                        switch (bfdm.getFileStatus())
                        {
                            case FILE_COMPLETE:
                                doOpen();
                                break;
                            case FILE_NOT_COMPLETE:
                                doDownload();
                                break;
                            case FILE_DOWNLOADING:
                                doPause();
                                break;
                            case FILE_DOWNLOAD_PAUSE:
                                doDownload();
                                break;
                        }

                        // 根据最新状态刷新UI显示
                        refreshUI(bfdm.getFileStatus());
                    }
                }
                // 当前界面中要查看的文件并不在下载任务管理器中
                else
                {
                    // 如果该文件本来就已经下载完成
                    if(isLocalFileCompelte())
                    {
                        Log.d(TAG, "【文件查看-非当前任务】initListeners调用中，用户可以直接打开文件，因为文件已就绪。");
                        // 直接尝试打开
                        doOpen();
                    }
                    // 否则进入下载流程
                    else
                    {
                        Log.d(TAG, "【文件查看-非当前任务】initListeners调用中，用户应是点击 doDownload()了");
                        doDownload();
                    }
                }
            }
            // 当文件不完整或不存在时不需要下载（这种情况对应用于我发出的文件消息）
            else
            {
                // 直接尝试打开
                doOpen();
            }
        });
    }

    /**
     * 初始化观察者类。
     */
    private void initObservers()
    {
        // 文件下载状态观察者
        this.downloadObserver = new BigFileDownloadManager.BigFileDownloadObserver()
        {
            BigFileDownloadManager bfdm = imc().getBigFileDownloadManager();

            @Override
            protected void onPreExecute(String fileMd5InManager)
            {
                if(bfdm.isCurrentFile(fileMd5))
                {
                    Log.d(TAG, "[观察者实现类中-当前任务] onPreExecute被调用了！");

                    _refreshUI();
                    showDownloadPregress(true);
                    showHint(null);
                }
                else
                {
                    Log.d(TAG, "[观察者实现类中-非当前任务] onPreExecute被调用了！");
                }
            }

            @Override
            protected void onProgressUpdate(String fileMd5InManager, Integer... progress)
            {
                if(bfdm.isCurrentFile(fileMd5))
                {
//                    Log.d(TAG, "[观察者实现类中-当前任务] onProgressUpdate被调用了！");

                    _refreshUI();
                    mDownloadProgress.setProgress(progress[0]);
                    showLocalFileSize();
                }
                else
                {
//                    Log.d(TAG, "[观察者实现类中-非当前任务] onProgressUpdate被调用了！");
                }
            }

            @Override
            protected void onPostExecute_onException(String fileMd5InManager, Exception exception)
            {
                if(bfdm.isCurrentFile(fileMd5))
                {
                    Log.d(TAG, "[观察者实现类中-当前任务] onPostExecute_onException被调用了！");

                    _refreshUI();
                    showHint("文件下载无法继续，请检查您的网络.");
                    Log.d(TAG, "【文件查看】文件下载停止了，原因是："+exception.getMessage());
                }
                else
                {
                    Log.d(TAG, "[观察者实现类中-非当前任务] onPostExecute_onException被调用了！");
                }
            }

            @Override
            protected void onPostExecute_onSucess(String fileMd5InManager, String fileSavedPath)
            {
                if(bfdm.isCurrentFile(fileMd5))
                {
                    Log.d(TAG, "[观察者实现类中-当前任务] onPostExecute_onSucess被调用了！");

                    _refreshUI();
                }
                else
                {
                    Log.d(TAG, "[观察者实现类中-非当前任务] onPostExecute_onSucess被调用了！");
                }
            }

            @Override
            protected void onCancel(String fileMd5InManager)
            {
                if(bfdm.isCurrentFile(fileMd5))
                {
                    Log.d(TAG, "[观察者实现类中-当前任务] onCancel被调用了！");

                    _refreshUI();
                }
                else
                {
                    Log.d(TAG, "[观察者实现类中-非当前任务] onCancel被调用了！");
                }
            }

            @Override
            protected void onPause(String fileMd5InManager)
            {
                if(bfdm.isCurrentFile(fileMd5))
                {
                    Log.d(TAG, "[观察者实现类中-当前任务] onPause被调用了！");
                    _refreshUI();
                }
                else
                {
                    Log.d(TAG, "[观察者实现类中-非当前任务] onPause被调用了！");
                }
            }

            private void _refreshUI()
            {
                if(bfdm.isCurrentFile(fileMd5))
                    refreshUI(bfdm.getFileStatus());
            }
        };
    }

    /**
     * 初始化文件的状态。
     */
    private void initFileStatusForUI()
    {
        // 当文件不完整或不存在时需要下载（这种情况对应于收到的文件消息）
        if(canDownload)
        {
            File f = this.getLocalFilePath();
            // 本界面要查看的文件已经就绪了(就不用管下载管理器的事，直接刷新ui)
            if(isLocalFileCompelte())
                refreshUI(BigFileDownloadManager.FileStatus.FILE_COMPLETE);
            else
            {
                Log.i(TAG, f.getAbsolutePath() + " 未下载完成。。。");

                // 大文件下载管理器
                BigFileDownloadManager bfdm = imc().getBigFileDownloadManager();

                // 当前界面中要查看的文件就是下载任务管理器中的文件
                if (bfdm.isCurrentFile(fileMd5))
                {
                    // 根据任务状态刷新界面上的UI显示（如按钮、进度条可见性等）
                    refreshUI(bfdm.getFileStatus());

                    // 如果有正在下载中或暂停中的作务，则还要把下载进度条及进度值显示出来
                    if(bfdm.isDownloading() || bfdm.isPause())
                        showDownloadPregress(true);
                }
                else
                {
                    // 根据任务状态刷新界面上的UI显示（如按钮、进度条可见性等）
                    refreshUI(BigFileDownloadManager.FileStatus.FILE_NOT_COMPLETE);
                    // 并刷新已经下载过的进度(在上次已经下载过一部分的情况下才需要显示，否则没意义)
                    if(this.getLocalFileCurrentLength() > 0)
                        showDownloadPregress(true);
                }
            }
        }
        // 当文件不完整或不存在时不需要下载（这种情况对应用于我发出的文件消息）
        else {
            // 根据任务状态刷新界面上的UI显示（如按钮、进度条可见性等）
            refreshUI(BigFileDownloadManager.FileStatus.FILE_COMPLETE);
        }
    }

    /**
     * 刷新按钮等相关UI的可见性。
     */
    private void refreshUI(BigFileDownloadManager.FileStatus fs)
    {
        switch(fs)
        {
            case FILE_COMPLETE:
                this.mBtnOpr.setText("打开文件");
                this.mBtnOpr.setBackgroundResource(R.drawable.common_btn_lightgreen_2019);
                this.mDownloadProgress.setVisibility(View.GONE);
                break;
            case FILE_NOT_COMPLETE:
                this.mBtnOpr.setText("下载文件");
                this.mBtnOpr.setBackgroundResource(R.drawable.common_btn_lightblue_2019);
                this.mDownloadProgress.setVisibility(View.GONE);
                break;
            case FILE_DOWNLOADING:
                this.mBtnOpr.setText("暂停下载");
                this.mBtnOpr.setBackgroundResource(R.drawable.common_btn_lightred_2019);
                this.mDownloadProgress.setVisibility(View.VISIBLE);
                break;
            case FILE_DOWNLOAD_PAUSE:
                this.mBtnOpr.setText("点击继续下载");
                this.mBtnOpr.setBackgroundResource(R.drawable.common_btn_lightblue_2019);
                this.mDownloadProgress.setVisibility(View.VISIBLE);
                break;
        }

        showLocalFileSize();
    }

    /**
     * 显示提示信息。
     * 
     * @param hint
     */
    private void showHint(String hint)
    {
        if(!CommonUtils.isStringEmpty(hint, true))
            this.mViewHint.setVisibility(View.VISIBLE);
        else
            this.mViewHint.setVisibility(View.GONE);

        this.mViewHint.setText(hint);
    }

    /**
     * 用最新的下载刷新当前文件大小的显示。
     */
    private void showLocalFileSize()
    {
        long curentDownloadLength = getLocalFileCurrentLength();
        if(curentDownloadLength <= 0 || curentDownloadLength == fileLength)
            this.mViewFileSize.setText(CommonUtils.getConvenientFileSize(fileLength, 2));
        else
            this.mViewFileSize.setText(CommonUtils.getConvenientFileSize(curentDownloadLength, 2)
                    +"/"+CommonUtils.getConvenientFileSize(fileLength, 2));
    }
    
    private File getLocalFilePath()
    {
        return new File(fileDir+File.separator+fileName);
    }
    
    private long getLocalFileCurrentLength()
    {
        return getLocalFilePath().length();
    }

    /**
     * 本界面中要打开的文件是否已完成（已下载完成）。
     *
     * @return
     */
    private boolean isLocalFileCompelte()
    {
        File f = this.getLocalFilePath();
        // 当前查看的文件已存在 且 该文件的实际大小跟文件消息中存放的完整文件大小是相等的，就表示该文件已完成（已下载完成）
        return f.exists() && f.length() == this.fileLength;
    }

    /**
     * 检查传进来的参数合法性。
     * 
     * @return
     */
    private boolean checkInitParams()
    {
        if(CommonUtils.isStringEmpty(fileName)
           || CommonUtils.isStringEmpty(fileDir)
           || fileLength <= 0)
        {
            WidgetUtils.showWithDialog(this, "提示", "无效的文件信息参数！");
            Log.w(TAG, "【文件查看】fileName="+fileName+", fileDir="+fileDir +", fileMd5="+fileMd5+", fileLen="+fileLength);
            return false;

        }
        return true;
    }

    /**
     * 刷新进条上的显示。
     * 
     * @param show true表示刷新显示，false表示隐藏进度条的显示
     */
    private void showDownloadPregress(boolean show)
    {
        if(show)
        {
            this.mDownloadProgress.setVisibility(View.VISIBLE);
            long curentDownloadLength = getLocalFileCurrentLength();
            int percent = 0;

            if (curentDownloadLength >= fileLength)
                percent = 100;
            else
                percent = (int) ((curentDownloadLength * 100) / fileLength);

            this.mDownloadProgress.setProgress(percent);
        }
        else
        {
            this.mDownloadProgress.setVisibility(View.GONE);
        }
    }

    /**
     * 开始下载/继续下载。
     */
    private void doDownload()
    {
        final BigFileDownloadManager bfdm = imc().getBigFileDownloadManager();

        Log.d(TAG, "【文件查看】[doDownload] bfdm="+bfdm+", bfdm.fileStatus="+bfdm.getFileStatus());
        bfdm.printDebug();

        if(!bfdm.isCurrentFile(fileMd5) && bfdm.isDownloading())
        {
            Log.d(TAG, "【文件查看】下载管理器中存在未完成的下载任务。。。");

            new AlertDialog.Builder(this)
                    .setTitle(R.string.general_prompt)
                    .setMessage("\""+bfdm.getFileName()+"\"正在后台下载中，开始新的下载前需先停止该文件的下载，确认要这样做吗？")
                    .setPositiveButton(R.string.general_yes, (dialog, which) -> {
                        // 先退出先前的下载任务
                        bfdm.cancelTask(true);
                        // 开始新的下载
                        doDownloadImpl(bfdm);
                    })
                    .setNegativeButton(R.string.general_no, null)
                    .show();
        }
        else
        {
            // 开始新的下载
            doDownloadImpl(bfdm);
        }
    }

    private void doDownloadImpl(BigFileDownloadManager bfdm)
    {
        if(checkInitParams())
        {
            if (bfdm != null)
            {
                long currentLength = getLocalFileCurrentLength();
                if (currentLength <= 0)
                    currentLength = 0;

                if (currentLength > fileLength)
                {
                    showHint("下载无法完成，原因是：文件大小异常.");
                    Log.w(TAG, "【文件查看】文下载无法完成，原因是：currentLength=" + currentLength + " > fileLength=" + fileLength);
                    return;
                }

                bfdm.startTask(fileMd5, currentLength, fileDir, this.fileName, fileLength);
            }
        }
    }

    /**
     * 暂停下载。
     */
    private void doPause()
    {
        final BigFileDownloadManager bfdm = imc().getBigFileDownloadManager();
        bfdm.pauseTask();
        refreshUI(bfdm.getFileStatus());
    }

    /**
     * 打开文件。
     */
    private void doOpen()
    {
        File f = this.getLocalFilePath();
        if(f.exists())
        {
            // 调用Android的系统intent尝试打开各种文件
            boolean sucess = OpenFileUtil.openFile(this, f.getAbsolutePath());
            if(!sucess)
            {
                WidgetUtils.showWithDialog(this, "友情提示", "没有找到可以打开此文件的程序，请安装相关程序后再试！");
            }
        }
        else
        {
            WidgetUtils.showWithDialog(this, "友情提示", "文件不存在，请稍后再试！");
        }
    }
    
    
    @Override
    protected DataFromServer queryData(String... arg0)
    {
        return null;
    }

    @Override
    protected void refreshToView(Object arg0)
    {
        //
    }

    /**
     * 返回对应扩展名的文件图标。
     * 
     * @param fileName
     * @return
     */
    public static int getFileIconDrawableId(String fileName)
    {
        int resId = R.drawable.file_type_unknow_big;

        String fileExtName = FileHelper.getFileExName(fileName);
        if(fileExtName != null)
        {
            fileExtName = fileExtName.toLowerCase();

            if("xls".equals(fileExtName) || "xlsx".equals(fileExtName))
                resId = R.drawable.file_type_excel_big;
            else if("gif".equals(fileExtName))
                resId = R.drawable.file_type_gif_big;
            else if("html".equals(fileExtName) || "htm".equals(fileExtName))
                resId = R.drawable.file_type_html_big;
            else if("jpg".equals(fileExtName) || "jpeg".equals(fileExtName))
                resId = R.drawable.file_type_jpg_big;
            else if("mp4".equals(fileExtName))
                resId = R.drawable.file_type_mp4_big;
            else if("pdf".equals(fileExtName))
                resId = R.drawable.file_type_pdf_big;
            else if("png".equals(fileExtName))
                resId = R.drawable.file_type_png_big;
            else if("ppt".equals(fileExtName) || "pptx".equals(fileExtName))
                resId = R.drawable.file_type_ppt_big;
            else if("rar".equals(fileExtName))
                resId = R.drawable.file_type_rar_big;
            else if("txt".equals(fileExtName))
                resId = R.drawable.file_type_txt_big;
            else if("apk".equals(fileExtName))
                resId = R.drawable.file_type_apk_big;
            else if("doc".equals(fileExtName) || "docx".equals(fileExtName))
                resId = R.drawable.file_type_word_big;
            else if("zip".equals(fileExtName)
                    ||"7z".equals(fileExtName)
                    ||"gz".equals(fileExtName)
                    ||"tar".equals(fileExtName))
                resId = R.drawable.file_type_zip_big;
        }

        return resId;
    }
}
